using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;

namespace System.Drawing.Imaging
{
  public unsafe class UnsafeBitmap
  {
    Bitmap bitmap;

    // three elements used for MakeGreyUnsafe
    int width;
    BitmapData bitmapData = null;
    Byte* pBase = null;

    public UnsafeBitmap(Bitmap bitmap)
    {
      this.bitmap = new Bitmap(bitmap);
    }

    public UnsafeBitmap(int width, int height)
    {
      this.bitmap = new Bitmap(width, height, PixelFormat.Format24bppRgb);
    }

    public void Dispose()
    {
      bitmap.Dispose();
    }

    public Bitmap Bitmap
    {
      get
      {
        return (bitmap);
      }
    }

    private Point PixelSize
    {
      get
      {
        GraphicsUnit unit = GraphicsUnit.Pixel;
        RectangleF bounds = bitmap.GetBounds(ref unit);

        return new Point((int)bounds.Width, (int)bounds.Height);
      }
    }

    public void LockBitmap()
    {
      GraphicsUnit unit = GraphicsUnit.Pixel;
      RectangleF boundsF = bitmap.GetBounds(ref unit);
      Rectangle bounds = new Rectangle((int)boundsF.X,
    (int)boundsF.Y,
    (int)boundsF.Width,
    (int)boundsF.Height);

      // Figure out the number of bytes in a row
      // This is rounded up to be a multiple of 4
      // bytes, since a scan line in an image must always be a multiple of 4 bytes
      // in length. 
      width = (int)boundsF.Width * sizeof(PixelData);
      if (width % 4 != 0)
      {
        width = 4 * (width / 4 + 1);
      }
      bitmapData =
    bitmap.LockBits(bounds, ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);

      pBase = (Byte*)bitmapData.Scan0.ToPointer();
    }

    public PixelData GetPixel(int x, int y)
    {
      PixelData returnValue = *PixelAt(x, y);
      return returnValue;
    }

    public void SetPixel(int x, int y, PixelData colour)
    {
      PixelData* pixel = PixelAt(x, y);
      *pixel = colour;
    }

    public void UnlockBitmap()
    {
      bitmap.UnlockBits(bitmapData);
      bitmapData = null;
      pBase = null;
    }
    public PixelData* PixelAt(int x, int y)
    {
      return (PixelData*)(pBase + y * width + x * sizeof(PixelData));
    }
  }
  public struct PixelData
  {
    public byte blue;
    public byte green;
    public byte red;
  }
}
